package org.example.myportfolio.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.example.myportfolio.dao.mapper.WorkFilesMapper;
import org.example.myportfolio.dao.mapper.WorkMapper;
import org.example.myportfolio.dao.repository.*;
import org.example.myportfolio.pojo.param.WorkFilesParam;
import org.example.myportfolio.pojo.param.WorksParam;
import org.example.myportfolio.pojo.po.WorkESPO;
import org.example.myportfolio.pojo.po.WorkFiles;
import org.example.myportfolio.pojo.po.WorkPO;
import org.example.myportfolio.pojo.vo.WorkVO;
import org.example.myportfolio.service.WorkService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WorkServiceImpl implements WorkService {

    @Autowired
    private WorkMapper workMapper;

    @Autowired
    private WorkFilesMapper workFilesMapper;

    @Autowired
    private WorkFileRepository workFileRepository;

    @Autowired
    private WorkRepository workRepository;

    @Autowired
    private WorkTagsRepository workTagsRepository;

    @Autowired
    private WorkESRepository workESRepository;


    //作品id
    private Long workId;


    /**
     *  @Transactional(rollbackFor = Exception.class)
     * 确保所有数据库操作都在一个事务中完成。
     * @param worksParam
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createWork(WorksParam worksParam) {
        log.debug("worksParam ID:{}",worksParam.getId());
        WorkPO workPO = new WorkPO();
        //1.插入作品
        saveWorkPO(worksParam,workPO);
        WorkFilesParam workFilesParam = worksParam.getWorkFilesParam();
        workId = workPO.getId();
        //2.插入作品文件
        saveWorkFiles(workFilesParam,workId);
        //3.插入标签tag
        saveTag2Work(worksParam,workId);
        //插入完成后获取主键id
        log.debug("workPO的id:{}",workId);
        return workId;
    }

    private void saveTag2Work(WorksParam worksParam, Long workId) {
        log.debug("标签入参：{}",worksParam.getTagId());
        int tagId = worksParam.getTagId();
        workTagsRepository.saveTag2Work(tagId,workId);

    }

    @Override
    public void deleteWork(Long workId) {
        log.debug("删除作品入参：{}",workId);
        WorkPO workPO = workMapper.selectById(workId);
        if(workPO == null){
            throw new IllegalArgumentException("作品不存在");
        }
        deleteWorkFilesByWorkId(workId);
        workMapper.deleteById(workId);
    }


    @Autowired
    private PageWorKCacheRepository pageWorKCacheRepository;


    /**
     * PageInfo 对象的结构：
     * PageInfo 是一个分页结果对象，它不仅包含数据列表，还包含其他分页相关的属性，如总记录数、当前页码、每页记录数等。
     * getList 方法返回的是实际的数据列表，即 List<T> 类型的对象
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public List<WorkVO> pageWork(Integer pageNum, Integer pageSize) {
        log.debug("pageNum:{},pageSize:{}",pageNum,pageSize);
        if(pageNum == null || pageNum <= 0 && pageSize == null || pageSize <= 0){
            log.error("页码或页大小为空");
            throw new IllegalArgumentException("页码不能小于1,页大小不能小于1");
        }else {
        //从redis中查询
        log.debug("开始从redis中查询分页作品集数据");
        PageInfo<WorkPO> workPOSList = null;
        workPOSList = pageWorKCacheRepository.pageWorkList(pageNum,pageSize);
        log.debug("从redis中查询分页作品集数据:{}",workPOSList.getList());
        if (workPOSList != null && workPOSList.getList() != null) { // 确保getList()不为空
            log.debug("从redis中查询分页作品集数据成功");
            return workPOSList.getList().stream()
                    .map(workPO -> {
                        WorkVO workVO = new WorkVO();
                        BeanUtils.copyProperties(workPO,workVO);
                        return workVO;
                    }).collect(Collectors.toList());
        }
        else {
            log.debug("从数据库中查询分页作品集");
            PageHelper.startPage(pageNum,pageSize);
            List<WorkPO> workPOS = workMapper.selectList(null);
            PageInfo<WorkPO> workPOList = new PageInfo<>(workPOS); //分页对象
            log.debug("从数据库中查询分页作品集成功:{}",workPOList);
            pageWorKCacheRepository.saveWorkList(pageNum,pageSize,workPOList);
            List<WorkVO> workVOS = workPOS.stream()
                    .map(workPO -> {
                        WorkVO workVO = new WorkVO();
                        BeanUtils.copyProperties(workPO,workVO);
                        return workVO;
                    }).collect(Collectors.toList());
            return workVOS;
        }
        }

    }

    @Override
    public void updateWork(WorksParam worksParam) {
        log.debug("更新作品入参：{}",worksParam);
        if(ObjectUtils.isNull(worksParam)){
           log.error("作品入参为空");
           throw new IllegalArgumentException("更新作品失败,作品入参为空");
        }
        Long workId = worksParam.getId();
        if(workId == null){
            log.error("作品id不能为空");
            throw new IllegalArgumentException("作品id不能为空");
        }
        try {
            workRepository.updateById(worksParam);
        } catch (Exception e) {
            log.error("更新作品失败:{}",e.getMessage(),e);
            throw new RuntimeException("更新作品失败",e);
        }
    }

    @Override
    public List<WorkVO> searchWorkByEs(String keyword) {
        log.debug("搜索作品入参：{}",keyword);
        if(StringUtils.isEmpty(keyword)){
            log.error("搜索关键字为空");
            throw new IllegalArgumentException("搜索关键字为空");
        }
        //从数据库查询作品集
        List<WorkPO> workESPOS = workMapper.selectList(null);

        //TODO 从ES中查询作品集
        List<WorkVO> workVOList = new ArrayList<>();
        return workVOList;

    }

    private void deleteWorkFilesByWorkId(Long workId) {
        workFileRepository.deleteByWorkId(workId);
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveWorkFiles(WorkFilesParam workFilesParam, Long workId) {
        if(workFilesParam == null){
            throw new IllegalArgumentException("作品文件参数不能为空");
        }
        validateWorkFilesParam(workFilesParam);

        WorkFiles workFiles = new WorkFiles();
        workFiles.setWorkId(workId);
        workFiles.setFilePath(workFilesParam.getFilePath());
        workFiles.setFileType(workFilesParam.getFileType());
        workFiles.setCreatedAt(LocalDateTime.now());
        log.debug("workFiles:{}",workFiles);
        try {
            workFilesMapper.insert(workFiles);
        } catch (Exception e) {
            log.error("作品文件插入失败:{}",e.getMessage(),e);
            throw new RuntimeException("作品文件插入失败",e);
        }
    }

    /**
     * 对文件类型和文件路径的长度进行校验
     * @param workFilesParam
     */
    private void validateWorkFilesParam(WorkFilesParam workFilesParam) {

        if (workFilesParam.getFilePath() == null || workFilesParam.getFileType() == null) {
            throw new IllegalArgumentException("文件路径和文件类型不能为空");
        }
        if(workFilesParam.getFilePath().length() > 255){
            throw new IllegalArgumentException("文件格式过长");
        }
        if(workFilesParam.getFileType().length() >50 ){
            throw new IllegalArgumentException("文件类型过长");
        }
    }

    private void saveWorkPO(WorksParam worksParam, WorkPO workPO) {
        if(worksParam == null || workPO == null){
            throw new IllegalArgumentException("参数不能为空");
        }
        workPO.setUserId(worksParam.getUserId());
        workPO.setTitle(worksParam.getTitle());
        workPO.setDescription(worksParam.getDescription());
        workPO.setCategoryId(worksParam.getCategoryId());
        workPO.setCreatedAt(new Date());
        log.debug("workPO:{}",workPO);
        try {
            workMapper.insert(workPO);
        } catch (Exception e) {
            log.error("作品插入失败:{}",e.getMessage(),e);
            throw new RuntimeException("作品插入失败",e);
        }
    }
}

/**
 * 1、报错信息明确
 * 2、确保事务的一致性，需要在方法上加注解@Transactional(rollbackFor = Exception.class)
 * 3、对文件类型和文件路径的长度进行校验
 */
